unit Wintun;

interface

uses
  Windows, SysUtils;

type
  NET_LUID = Int64;

  // Wintun 适配器句柄
  WINTUN_ADAPTER_HANDLE = Pointer;

  // Wintun 会话句柄
  WINTUN_SESSION_HANDLE = Pointer;

  // 日志级别枚举
  WINTUN_LOGGER_LEVEL = (WINTUN_LOG_INFO, WINTUN_LOG_WARN, WINTUN_LOG_ERR);

  // WINTUN_LOGGER_CALLBACK 类型声明
  WINTUN_LOGGER_CALLBACK = procedure(Level: WINTUN_LOGGER_LEVEL; Timestamp: Int64; const Message: PWideChar); stdcall;

  // 函数原型

  {
   * 创建一个新的 Wintun 适配器。
   *
   * @param Name          适配器的名称，最多 MAX_ADAPTER_NAME-1 字符的零终止字符串。
   * @param TunnelType    适配器隧道类型的名称，最多 MAX_ADAPTER_NAME-1 字符的零终止字符串。
   * @param RequestedGUID 如果为 NULL，则由系统随机选择 GUID，否则使用给定的 GUID 来创建适配器。
   * @return 如果成功，返回适配器句柄。必须使用 WintunCloseAdapter 释放该句柄。如果失败，返回 NULL。
   *         若要获取扩展的错误信息，调用 GetLastError。
   }
  function WintunCreateAdapter(Name, TunnelType: PWideChar; RequestedGUID: PGUID): WINTUN_ADAPTER_HANDLE; stdcall; external 'wintun.dll';

  {
   * 打开一个已有的 Wintun 适配器。
   *
   * @param Name          适配器的名称，最多 MAX_ADAPTER_NAME-1 字符的零终止字符串。
   * @return 如果成功，返回适配器句柄。必须使用 WintunCloseAdapter 释放该句柄。如果失败，返回 NULL。
   *         若要获取扩展的错误信息，调用 GetLastError。
   }
  function WintunOpenAdapter(Name: PWideChar): WINTUN_ADAPTER_HANDLE; stdcall; external 'wintun.dll';

  {
   * 释放 Wintun 适配器资源，如果适配器是通过 WintunCreateAdapter 创建的，还会移除该适配器。
   *
   * @param Adapter       通过 WintunCreateAdapter 或 WintunOpenAdapter 获得的适配器句柄。
   }
  procedure WintunCloseAdapter(Adapter: WINTUN_ADAPTER_HANDLE); stdcall; external 'wintun.dll';

  {
   * 如果没有适配器在使用，则删除 Wintun 驱动程序。
   *
   * @return 如果成功，返回非零值。如果失败，返回零。若要获取扩展的错误信息，调用 GetLastError。
   }
  function WintunDeleteDriver: Boolean; stdcall; external 'wintun.dll';

  {
   * 获取适配器的 LUID（本地唯一标识符）。
   *
   * @param Adapter       通过 WintunCreateAdapter 或 WintunOpenAdapter 获得的适配器句柄。
   * @param Luid          指向接收适配器 LUID 的指针。
   }
  procedure WintunGetAdapterLUID(Adapter: WINTUN_ADAPTER_HANDLE; var Luid: NET_LUID); stdcall; external 'wintun.dll';

  {
   * 获取当前运行的 Wintun 驱动程序版本。
   *
   * @return 如果成功，返回版本号。如果失败，返回零。若要获取扩展的错误信息，调用 GetLastError。
   *         可能的错误包括 ERROR_FILE_NOT_FOUND（Wintun 未加载）。
   }
  function WintunGetRunningDriverVersion: DWORD; stdcall; external 'wintun.dll';

  {
   * 设置日志回调函数。
   *
   * @param NewLogger     新的日志回调函数，可以为 NULL 来禁用日志功能。
   }
  procedure WintunSetLogger(NewLogger: WINTUN_LOGGER_CALLBACK); stdcall; external 'wintun.dll';

  {
   * 启动 Wintun 会话。
   *
   * @param Adapter       通过 WintunOpenAdapter 或 WintunCreateAdapter 获得的适配器句柄。
   * @param Capacity      环形缓冲区的容量，必须在 WINTUN_MIN_RING_CAPACITY 和 WINTUN_MAX_RING_CAPACITY 之间。
   *                      必须是 2 的幂。
   * @return 返回 Wintun 会话句柄，必须使用 WintunEndSession 释放该句柄。如果失败，返回 NULL。
   *         若要获取扩展的错误信息，调用 GetLastError。
   }
  function WintunStartSession(Adapter: WINTUN_ADAPTER_HANDLE; Capacity: DWORD): WINTUN_SESSION_HANDLE; stdcall; external 'wintun.dll';

  {
   * 结束 Wintun 会话。
   *
   * @param Session       通过 WintunStartSession 获得的 Wintun 会话句柄。
   }
  procedure WintunEndSession(Session: WINTUN_SESSION_HANDLE); stdcall; external 'wintun.dll';

  {
   * 获取会话的读取等待事件句柄。
   *
   * @param Session       通过 WintunStartSession 获得的 Wintun 会话句柄。
   * @return 返回一个事件句柄，用于等待可用数据。不要调用 CloseHandle 来关闭该事件句柄——它由会话管理。
   }
  function WintunGetReadWaitEvent(Session: WINTUN_SESSION_HANDLE): THANDLE; stdcall; external 'wintun.dll';

  {
   * 从 Wintun 会话接收一个数据包。
   *
   * @param Session       通过 WintunStartSession 获得的 Wintun 会话句柄。
   * @param PacketSize    接收数据包大小的指针。
   * @return 返回一个指向 IP 数据包（IPv4 或 IPv6）的指针，客户端可以修改数据包内容。
   *         如果失败，返回 NULL。若要获取扩展的错误信息，调用 GetLastError。
   *         可能的错误包括 ERROR_HANDLE_EOF（Wintun 适配器正在终止）；ERROR_NO_MORE_ITEMS（Wintun 缓冲区已耗尽）。
   }
  function WintunReceivePacket(Session: WINTUN_SESSION_HANDLE; var PacketSize: DWORD): PByte; stdcall; external 'wintun.dll';

  {
   * 释放接收到的数据包。
   *
   * @param Session       通过 WintunStartSession 获得的 Wintun 会话句柄。
   * @param Packet        通过 WintunReceivePacket 获得的数据包。
   }
  procedure WintunReleaseReceivePacket(Session: WINTUN_SESSION_HANDLE; Packet: PByte); stdcall; external 'wintun.dll';

  {
   * 为发送的数据包分配内存。
   *
   * @param Session       通过 WintunStartSession 获得的 Wintun 会话句柄。
   * @param PacketSize    要分配的准确数据包大小，不能超过 WINTUN_MAX_IP_PACKET_SIZE。
   * @return 返回一个指向内存的指针，用于填充数据包内容。如果失败，返回 NULL。
   *         若要获取扩展的错误信息，调用 GetLastError。可能的错误包括 ERROR_HANDLE_EOF（Wintun 适配器正在终止）。
   }
  function WintunAllocateSendPacket(Session: WINTUN_SESSION_HANDLE; PacketSize: DWORD): PByte; stdcall; external 'wintun.dll';

  {
   * 发送已分配的数据包。
   *
   * @param Session       通过 WintunStartSession 获得的 Wintun 会话句柄。
   * @param Packet        通过 WintunAllocateSendPacket 获得的数据包。
   }
  procedure WintunSendPacket(Session: WINTUN_SESSION_HANDLE; Packet: PByte); stdcall; external 'wintun.dll';

const
  // 最小环形缓冲区容量
  WINTUN_MIN_RING_CAPACITY = $20000; // 128KiB

  // 最大环形缓冲区容量
  WINTUN_MAX_RING_CAPACITY = $4000000; // 64MiB

  // 最大 IP 数据包大小
  WINTUN_MAX_IP_PACKET_SIZE = $FFFF; // 65535 字节

implementation

end.
